home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / docs.lha / internals / dave-memory-layout.mss < prev    next >
Text File  |  1991-11-12  |  33KB  |  617 lines

  1. @device[Postscript]
  2. @make[Article]
  3. @style[FontFamily "TimesRoman"]
  4. @pageheading[]
  5. @pagefooting[center "@value<page>"]
  6. @newpage(1)
  7. @begin[Center]
  8. @heading[CMU Common Lisp Memory Layout under New Type Scheme]
  9. @b[David B. McDonald]
  10. @value[Date]
  11. @end[Center]
  12.  
  13. @section[Introduction]
  14.  
  15. This document describes some ideas on how to layout memory under
  16. the new type scheme for CMU Common Lisp.  There are many issues that are
  17. involved in this design.  Each of the important issues that I have been
  18. able to identify is examined in a separate section.  In each section two
  19. possible alternatives are proposed: one that assumes the default Unix
  20. 4.3BSD environment and one that assumes the significantly more advanced
  21. Mach environment.  Throughout this document, I will use Unix to mean a
  22. non-Mach version of Unix, such as Berkeley 4.3BSD.
  23.  
  24. Section @ref[differences] describes the features of current Unix and Mach
  25. systems that affect the design.  Section @ref[layout] describes a possible
  26. memory layout scheme under both Unix and Mach.  Section @ref[Stacks]
  27. describes how the stacks should be layed out.  Section @ref[management]
  28. describes how memory could be allocated and managed with the new type
  29. scheme.  Section @ref[garbage] describes how garbage collection could work
  30. under the new type scheme assuming a simple stop and copy garbage
  31. collector.  Section @ref[genesis] describes how an initial kernel Lisp core
  32. file is generated.  Section @ref[ccode] describes how C code should be
  33. loaded into a running Lisp.  Section @ref[Purification] describes some idea
  34. on what the purification process should do to reduce the amount of work for
  35. the garbage collector.  Section @ref[saving] describes how Lisp core files
  36. can be created so that the Lisp environment of a running process can be
  37. restored and run at a later time.  Finally, section @ref[Summary]
  38. summarizes what I believe is a reasonable approach to memory layout with
  39. the new type scheme.
  40.  
  41. @section[Mach vs. Unix]
  42. @label[Differences]
  43.  
  44. Mach is a superset of Unix, so a design that relied on Mach without paying
  45. any attention to Unix would be more flexible and easier to implement.
  46. However, if CMU Common Lisp is going to run on non-Mach Unix systems, it is
  47. important to understand some of the short comings of these systems.  In the
  48. following discussion, I am assuming a standard Unix 4.3BSD environment.
  49. Some vendor Unix systems, such as Dec's Ultrix or Sun's SunOs, may provide
  50. some or all of the features that make Mach a better operating to which to
  51. port Lisp.  I don't have documentation on these, so don't know what if any
  52. features these systems support.
  53.  
  54. The following features are important to the design:
  55. @begin[Description]
  56. text segment@\The text segment contains the code for a process.  This
  57. segment normally starts at address #x0.  This is true for Mach.  The
  58. important aspect about the text segment is that it is shared amongst all
  59. the process running the same program.  For Lisp, in a Unix environment,
  60. this means it is important to have as much of the Lisp code and read-only
  61. data in this segment as possible to allow sharing.  This segment is
  62. protected read-only by the operating system -- writing to it is not allowed
  63. and will cause a segment violation.  There is a separate part of an a.out
  64. file that contains the text segment.
  65.  
  66. data segment@\The data segment contains the data for a process.  This
  67. segment normally starts at the beginning of the page after the end of the
  68. text segment.  On the IBM RT PC it starts at #x10000000 instead.  An a.out
  69. file contains two pieces of information for the data segment.  The first is
  70. the size of the initialized data which is contained in the a.out file so
  71. that the data segment is initialized properly.  The second piece of
  72. information is the size of the uninitialized data which when a program is
  73. loaded immediately follows the initialized data and is initialized to zero.
  74.  
  75. stack segment@\The stack segment contains the Unix user stack.  This stack
  76. is normally near the high end of the address space and grows downwards
  77. toward the end of the data segment.  An a.out files contains no
  78. information about the stack segment.  Unix normally sets up the stack so
  79. that if it overflows, more memory is allocated automatically without the
  80. running process ever detecting anything.  On the IBM RT PC, the stack
  81. segment starts at #xDFFFFFFC and grows downward.
  82.  
  83. memory allocation@\Memory allocation is where Unix and Mach diverge.  On a
  84. Unix system, it is only possible to allocate memory at the end of the data
  85. segment by using the brk system call.  There are subroutine libraries built
  86. on top of this that provide more flexible allocation.  The memory allocated
  87. is always writable and there is no provision made to set the protection of
  88. this memory to no access (useful for guard pages of stacks and generational
  89. garbage collection) or read-only (useful for generation garbage
  90. collection).  Note that any call out to C code could cause memory to be
  91. allocated by the brk system call either directly or through the subroutine
  92. libraries (e.g., malloc and free).
  93.  
  94. file mapping@\Unix does not currently provide any facility for mapping
  95. files into the address space of a process.  A similar effect can be
  96. achieved by reading a file into memory.  However, no sharing is possible as
  97. there is in Mach with its read-only or copy-on-write file mapping.
  98. @end[Description]
  99.  
  100. A convenient memory layout for the new CMU Common Lisp implementation would
  101. use the standard a.out executable file format and the brk memory allocation
  102. calls.  This would allow CMU Common Lisp to run on less advanced versions
  103. of Unix than Mach.  However, the Mach memory allocation and file mapping
  104. calls provide a degree of flexibility that make using the standard Unix
  105. calls, as they currently exist, difficult at best.  Some of the current
  106. Unix BSD documentation contains definitions of unimplemented system calls
  107. that provide appropriate memory primitives such as allocation, protection,
  108. and file mapping that would allow Lisp to run on non-Mach machines without
  109. as much trouble.
  110.  
  111. @section[Basic Memory Layout]
  112. @label[layout]
  113.  
  114. The basic memory layout, assuming an a.out file format for Lisp save files
  115. follows (a similar layout could be used for Mach, although this is not
  116. necessary):
  117. @begin[Verbatim]
  118.     +-------------------------------------------------------+
  119.     |    C start up code                    |
  120.     +-------------------------------------------------------+
  121.     |    Lisp Miscops (Lisp assembler)            |
  122.     +-------------------------------------------------------+
  123.     |    Lisp read only data                |
  124.     +-------------------------------------------------------+
  125.     |    Gap 1                        |
  126.     +-------------------------------------------------------+
  127.     |    C data                        |
  128.     +-------------------------------------------------------+
  129.     |    Miscop data                    |
  130.     +-------------------------------------------------------+
  131.     |    Lisp static data                |
  132.     +-------------------------------------------------------+
  133.     |    Gap 2                        |
  134.     +-------------------------------------------------------+
  135.     |    Lisp dynamic 0 data                |
  136.     +-------------------------------------------------------+
  137.     |    Lisp dynamic 1 data                |
  138.     +-------------------------------------------------------+
  139.     |    Gap 3                        |
  140.     +-------------------------------------------------------+
  141.     |    C stack                        |
  142.     +-------------------------------------------------------+
  143. @end[Verbatim]
  144.  
  145. The meaning of the above areas and what they contain is as follows:
  146. @begin[Description]
  147. C Start Up Code@\This area would correspond to the current lisp start up
  148. code.  It would gain control from the operating system when lisp is run,
  149. pass in the environment and command line switches to Lisp, pick up
  150. the Lisp starting point from a known location and jump into Lisp code.
  151. This code would include the socket.o file that is necessary to open a
  152. connection to the X11 server.
  153.  
  154. Lisp Miscops@\This area would contain all the Lisp miscops including
  155. assembler routines and compiled miscops (e.g., bignum code).
  156.  
  157. Lisp Read Only Data@\This area would contain all the data in the default
  158. Lisp process that is read-only.  This would include the combined
  159. function/code objects, documentation strings, symbol names, etc. that
  160. should never be modified.
  161.  
  162. Gap 1@\There may be a region of memory between the end of the Lisp read
  163. only data and the beginning of C data.  On the IBM RT PC, there
  164. is a gap since C code would start at #x0 and C data would start
  165. at #x10000000.  On the Sun there isn't this separation between C code
  166. and data, so there may be no gap at all.  The advantage of having a gap is
  167. that during the purification/save process for non system cores, read-only
  168. data could be moved into the Lisp read only area.
  169.  
  170. C Data@\This area contains the C data from the Lisp start up code.
  171.  
  172. Miscop Data@\This area contains any data areas the Lisp miscops need.  For
  173. example, allocation information should be accessible from miscops.
  174. Allowing for miscop data requires enhancing the assembler to allow for
  175. resolving these addresses at miscop load time.  The current miscops use a
  176. fixed location in memory to hold any data they need.  This scheme is
  177. inappropriate on non Mach operating systems.
  178.  
  179. Lisp Static Data@\This area contains all the Lisp data from the default
  180. Lisp process that must be writable.  This would include symbols, strings
  181. that are used as buffers, arrays, vectors, etc.  In user saved Lisp
  182. files, this area should also include any C or foreign code loaded into Lisp.
  183.  
  184. Gap 2@\A relatively small gap should exist, so that it is possible to
  185. allocate more data to static space without having to move dynamic space
  186. around.
  187.  
  188. Lisp Dynamic 0 Data@\This area is where Lisp starts allocating new dynamic
  189. objects when it first starts.  A saved Lisp file may contain some initial
  190. data in this area.
  191.  
  192. Lisp Dynamic 1 Data@\The first GC will copy objects from the Lisp dynamic 0
  193. data area to here and then flip back and forth between these two areas.
  194.  
  195. Gap 3@\For both Mach and Unix, there will be a gap between the end of
  196. dynamic space and the C stack.
  197.  
  198. C Stack@\The C stack contains control information for the C start up code,
  199. including environment information and command line switches.
  200. @end[Description]
  201.  
  202. The important thing to notice about the above layout is that it is possible
  203. to use the Unix a.out file format to represent a Lisp save file.  This is
  204. not important under Mach since file mapping is available and the various
  205. areas could lie anywhere in memory.  However, on non-Mach systems there is
  206. far less flexibility on where these areas can be located.
  207.  
  208. The addresses, at which each of the areas described above start, depend on the
  209. particular machine and operating system.  For example, on the IBM RT PC the
  210. C Start Up code starts at #x0, the Lisp Miscops would immediately follow,
  211. and then the Lisp Read Only Data.  In Unix terminology these three areas
  212. would correspond to the text segment of an a.out file.  This means they
  213. would be shared among all the processes running Lisp even on non Mach
  214. machines.  The C Data starts at #x10000000, miscop data and the Lisp static
  215. data would immediately follow.  In Unix terminology, this would correspond
  216. to the initialized data segment.  The Lisp Dynamic 0 and 1 data areas
  217. should be allocated after this area.  Note that if there is any dynamic
  218. data in the Lisp save file, it would follow the Lisp static area and be
  219. part of the initialized data segment.  A gap of several pages should be
  220. left free between static and dynamic 0 data to allow static data to grow
  221. without causing a major garbage collection.
  222.  
  223. Note that nothing has been said about the location of the Lisp stacks.  The
  224. following section describes stacks in more detail.  The location of these
  225. stacks depend on whether Mach or Unix semantics are used.
  226.  
  227. @section[Stacks]
  228. @label[Stacks]
  229.  
  230. The new implementation of CMU Common Lisp appears to require the use of
  231. three stacks:
  232. @begin[description]
  233. control stack@\The control stack contains information about the flow
  234. of control of a Lisp computation.  This would include information about
  235. catch points for non-local exits, save areas for registers that must be
  236. preserved across function boundaries (including return points), and local
  237. variables that do not fit into registers.  The control stack must contain
  238. only Lisp objects since it must be scanned by the garbage collector.
  239.  
  240. binding stack@\The binding stack contains binding information for special
  241. variables.  As a computation progresses, special symbols and their old
  242. values are stored on this stack as these variables are bound.  As a
  243. computation unwinds, this information is used to restore the old value to
  244. the symbol.  The binding stack must contain only lisp objects since it must
  245. be scanned by the garbage collector.
  246.  
  247. non-lisp (or number) stack@\The non-lisp stack contains thirty-two bit
  248. objects that must never be processed by the garbage collector.  This stack
  249. is necessary to allow writing portable number code in Lisp.  I strongly
  250. recommend that the standard Unix stack be used for this purpose.  This has
  251. no disadvantages that I can think of other than reserving the standard C
  252. register for this stack which on machines with thirty-two registers is not
  253. a problem.  It has the advantage that system calls, calling out to C
  254. routines, and interrupt processing will be easier and more efficient.
  255. Also, in some Unix versions, the register containing the stack is treated
  256. specially and Lisp using it for something else may be dangerous.
  257. @end[Description]
  258.  
  259. There is one important consideration in the design of where these various
  260. stacks are located in memory.  Pointers into any of the above three stacks
  261. will look like fixnums to the system, so it will be difficult to move the
  262. stacks around once they have been allocated.  I believe there are two main
  263. avenues to follow here depending on whether Mach features are used or only
  264. those available in standard Unix.
  265.  
  266. Using Mach features, I believe the following stack scheme is the correct
  267. way to go.  I am going to use stack locations that make sense for the IBM
  268. RT PC version of Mach.  Other versions of Mach may use slightly different
  269. locations.
  270. @begin[Description]
  271. control stack@\The control stack should start at location #xBFFFFFFC and
  272. grow downward.
  273.  
  274. binding stack@\The binding stack should start at location #xCFFFFFFC and
  275. grow downward.
  276.  
  277. non-lisp stack@\The non-lisp or number stack should be the Unix stack and
  278. starts at #XDFFFFFFC and grows downward.
  279. @end[Description]
  280. The advantage of this scheme is the stacks are separate so the GC needs no
  281. knowledge about the structure of the stacks.  Also, they are at fixed
  282. locations and it is easy to restore a saved Lisp using the Mach map_fd call.
  283. Each stack can be up to 256 megabytes before overflow occurs.  This should
  284. be large enough for some time to come.  The control stack could actually
  285. grow bigger since it has only have dynamic memory below it and they will be
  286. separated by a large amount of space.  Interrupt handling should be fairly
  287. straight forward since the initial interrupt information could automatically be
  288. stored on the Unix stack.  An interrupt stack frame will be created on the
  289. Lisp control stack and any information that is necessary for Lisp can be
  290. copied from the Unix stack to the Lisp control stack.
  291.  
  292. For Unix, there are a couple of possible solutions to the stack problem.  One
  293. solution is to put the control and binding stacks before or after static
  294. space.  These stacks would be of fixed size and could not grow since it
  295. would be hard to move them because stack pointers would be difficult to
  296. find.  To increase the size of the stacks, it would be necessary to rebuild
  297. the system.  Also, the entirety of both stacks would have to be saved in a
  298. Lisp save file no matter if only one page was in use.
  299.  
  300. Another solution is to combine all of the stacks.  This is probably the
  301. correct solution for Unix, but introduces significant complexities.  Each
  302. Lisp stack frame would have to have enough information so that the Garbage
  303. collector could parse the frame.  In particular, each frame would need to
  304. be divided into non-Lisp space and Lisp only space.  Also, it would have to
  305. have a pointer to the previous active frame on the stack.  Any stack
  306. information outside of a stack frame would be ignored by the garbage
  307. collector.  A stack frame needs to specify which locations contain non-Lisp
  308. data and which contain Lisp data.  The active frame pointer can be used to
  309. chase down the stack frames and GC the objects in the Lisp parts of each
  310. frame.  This means the active frame pointer must always be valid when a GC
  311. occurs.  Open but not active frames would be part of the frame for the
  312. function building the open frame.  One problem is dealing with an arbitrary
  313. number of multiple values coming back from a function.  If these come back
  314. on the stack, the Lisp/non-lisp information may need to be updated by the
  315. multiple-value return mechanism to make sure everything is in a legal
  316. state.  The binding stack would use a mechanism similar to unwind-protect
  317. to restore old symbol values.  Call out to C should be handled by using a
  318. frame on the stack that is outside the caller's stack frame and thus not
  319. part of the frame -- GC will ignore it.  Interrupts can be handled in one
  320. of two ways:
  321. @begin[Itemize]
  322. An interrupt frame will be created on the stack and an interrupt handler
  323. called.  While interrupts are disabled, the interrupt handler would be
  324. responsible for cleaning up the stack to make sure that it is consistent.
  325. It should copy the interrupt information that the Lisp interrupt processor
  326. needs and return from the interrupt causing control to pass to the real
  327. interrupt handler that can set up a legal Lisp frame (interrupts must still
  328. be disabled at this point).
  329.  
  330. Have a separate interrupt stack as is done in the current system.  A fixed
  331. location before or after the static region would be a likely candidate for
  332. this.
  333. @end[Itemize]
  334. Saving the stack could be done by copying the contents into the a.out file
  335. just after the static space area.  On restoring the file, it would be
  336. necessary to copy this information into the Unix stack (normally this will
  337. be a couple of pages).
  338.  
  339. @section[Memory Management]
  340. @label[management]
  341.  
  342. Under Mach, using vm_allocate and vm_deallocate to allocate and free memory
  343. used for dynamic space is a big advantage.  Lisp doesn't have to
  344. worry about where this memory is and new dynamic space will be zero-fill
  345. pages.  This is much more efficient than under Unix where the new dynamic
  346. space (after the first GC) will contain old garbage and has to be paged in
  347. from disk.  Under Mach, even if brk memory allocation is used, it will be
  348. wise to vm_deallocate and vm_allocate old space so that they are zero fill
  349. pages.
  350.  
  351. Under Unix, when Lisp starts up it must use the brk system call to allocate
  352. a chunk of memory, half of which will be used for dynamic 0; the other half
  353. for dynamic 1.  The amount of space actually allocated should be specified
  354. by a command line switch.  If dynamic memory usage grows sufficiently to
  355. require more memory to allocate, it will be necessary to allocate more
  356. memory to both dynamic spaces.  However, it is not possible to guarantee
  357. that the new memory allocated will be contiguous with the top of dynamic 1
  358. because C routines that have been called may have called the brk system
  359. call or more likely used a library call to allocate more memory.
  360.  
  361. It is convenient for the two dynamic memory areas to be the same size and
  362. each one to be contiguous.  However, since under Unix there is no way to
  363. guarantee that the memory allocated with brk will be contiguous, a scheme
  364. that allows Lisp and non-Lisp memory to be intermingled may be necessary.  A
  365. possible scheme is to have chunks of memory of some fixed size (e.g., 64K
  366. or 128K bytes) and do allocation in terms of these.  This means the garbage
  367. collector and variable length allocation routines become more complicated.
  368. When one region of memory is exhausted there may be another that should be
  369. used.
  370.  
  371. Another possibility is to allow memory to expand only once effectively
  372. doubling the size of each dynamic space.  This could be done by combining
  373. the original dynamic 0 and dynamic 1 space into dynamic 0 space and
  374. allocating a chunk of memory of the same size.  Note a check could be made
  375. to see if the new memory will be contiguous and then Lisp could grow more
  376. slowly with doubling used as a last resort.  It is also possible for Lisp
  377. to provide its own version of the C allocation calls.  The only problem
  378. with this is that a C or assembler program could invoke the brk system call
  379. directly without going through the normal library routines.
  380.  
  381.  
  382. @section[Garbage Collection]
  383. @label[garbage]
  384.  
  385. Garbage collecting should be fairly straight forward.  With two dynamic
  386. spaces, it is necessary only to copy the accessible objects from old
  387. dynamic space to new dynamic space.
  388.  
  389. Under Mach, when a GC is triggered, the following should be done:
  390. @begin[Enumerate]
  391. Use vm_allocate to allocate at least as much space as is currently being
  392. used by the old dynamic space.  The amount allocated could be increased
  393. some if a lot of data was kept the last time a GC was performed.
  394.  
  395. Scan the roots of Lisp moving any Lisp objects from old dynamic space to
  396. new dynamic space leaving GC forward pointers behind..  The roots of Lisp
  397. would include the Lisp registers, control and binding stack, and static
  398. space.
  399.  
  400. Scavenge new dynamic space.  That is, all the objects in new dynamic space
  401. that contain Lisp object must be scanned for pointers into old space.  All
  402. accessible objects in old space must be transported to new space.
  403.  
  404. Use vm_deallocate to deallocate the old dynamic space, since it is no
  405. longer in use.
  406. @end[Enumerate]
  407. The above GC algorithm should work well under Mach.  There only needs to be
  408. a free pointer (the first free location in new dynamic space) and an end
  409. pointer (the first location that is unusable).  On a machine with 32
  410. registers, these might as well be in registers.  On other machines, leaving
  411. these in memory is probably best.
  412.  
  413. Under Unix, a similar algorithm could be used, but if new dynamic space is
  414. not contiguous because of C allocation problems, GC will have to be more
  415. complicated.  It may have to allocate large objects in a different area
  416. than the current allocation area.
  417.  
  418. @section[Genesis]
  419. @label[genesis]
  420.  
  421. There are two options with genesis.  If the a.out file format is used for
  422. Lisp save files as it should if only Unix features are used, then Genesis
  423. will have to be modified heavily.  If Mach memory allocation and file
  424. mapping features are used, the the current Genesis can be used without too
  425. much modification.  Although, it would make sense to have a way for data
  426. areas used by the miscops to be allocated at miscop load time and any
  427. references to these areas be resolved by genesis rather than using fixed
  428. memory location as is currently done.
  429.  
  430. If the Unix a.out format is used, Genesis must be modified to generate an
  431. a.out executable file rather than the current Lisp core file format.  I do
  432. not believe that this is difficult.  To use the a.out format, the following
  433. sequence of operations need to be performed:
  434. @begin[Enumerate]
  435. Read the C start up file object code and allocate space for it at the front
  436. of what will become the text segment.  Allocate space for the C data at the
  437. start of what will be come the data segment.  Note: On the IBM RT PC this
  438. is straight forward and can be done easily from the executable file created
  439. by ld, since text starts at #x0 and data starts at #x10000000.  On other
  440. machines it will be necessary to make sure that the data segment starts at
  441. a location high enough to allow space for all the Lisp read-only data.
  442. This may be done using ld switches or by having a small assembler language
  443. routine that allocates a few megabytes of space in the text segment.
  444.  
  445. Read the Lisp miscop files and place them in the text segment after the C
  446. code.  Note that some of the current miscops need to access fixed memory
  447. locations.  A more ambitious scheme would allow the assembler to define
  448. data areas for the miscops that need data.  The allocation tables needed by
  449. Lisp are an example where this is would be useful.  If this scheme is
  450. adopted, these data structures would be allocated after the C data.
  451.  
  452. The Lisp files needed to run a kernel core should now be loaded.  All
  453. code/function objects should be allocated in the text segment.  All other
  454. objects should be loaded in the data segment.  This is not an optimal
  455. arrangement.  Certain strings (e.g., documentation strings and symbol
  456. names) and other constants should also be put in the text segment.  This
  457. requires the compiler to generate information so that the cold loader knows
  458. what objects are read-only.
  459.  
  460. Write out an a.out file with the new text and data segments created by the
  461. above process.  Also the symbol table information contained in the original
  462. C start up code for Lisp should be copied to this file so that loading of
  463. foreign functions can use this symbol table information.
  464. @end[Enumerate]
  465.  
  466. @section[Loading C code]
  467. @label[ccode]
  468.  
  469. Loading C code should be relatively simple.  As is currently done, it will
  470. be necessary to run ld with the appropriate switches to generate an
  471. incremental load file using the lisp executable file as the base (or the
  472. most recent intermediate file created by a previous load of foreign code in
  473. the currently running Lisp).  This incremental load file should be linked
  474. so that it will be placed at the end of the current lisp static area.
  475.  
  476. A problem that may occur here is that the space between the end of the
  477. current static area and the beginning of dynamic 0 space is too small for
  478. the resulting object file.  In this case, it is necessary to perform a
  479. garbage collection so that more space can be allocated to static space from
  480. dynamic 0 space.
  481.  
  482. @section[Purification]
  483. @label[purification]
  484.  
  485. Purification should not be as necessary in the new system as it was in the
  486. old.  With all the functions in a file contained in one combined
  487. function/code object, the function object and code vector will always be
  488. near one another.  The important thing to do with purification is to make
  489. sure that all the constants pointed at by a function/code object be near
  490. it.  The only things that may cause problems are symbols, because other
  491. constants should be near the function/code object since they are
  492. loaded at the same time.  Also, some function/code objects should be near
  493. one another if they share a large number of constants.  Initially,
  494. I don't think it is necessary to implement purification.  At some time in
  495. the future purification should be combined with the save Lisp process so
  496. that the Lisp save file has somewhat better locality than it would
  497. otherwise.
  498.  
  499. In the future the purification process should be done while a Lisp core
  500. file is being saved.  This will allow the system to write out either an
  501. a.out file format or the current Lisp core file format file in which
  502. everything may have been relocated to reduce the amount of paging.
  503. Purification should effectively do a complete GC of read-only, static, and
  504. dynamic space relocating everything into read-only and static space with
  505. all objects relocated so that function/code objects that call one another
  506. or share many constants are near one another.  The information necessary to
  507. do this can be retrieved from the function/code objects.  The number of
  508. references to an object from a function/code object could be obtained, but
  509. it probably isn't worth the effort.  Using the reference information, a
  510. better ordering of all Lisp objects could be made.
  511.  
  512. @section[Saving Lisp Cores]
  513. @label[saving]
  514.  
  515. There are two options for saving a Lisp core file.  One is to use the a.out
  516. format which would be the preferred method if Unix is to be supported.
  517. Under Mach, retaining the current (or similar) format has some advantages.
  518. In particular, all the memory allocation and stack problems are no longer
  519. something to worry about.  The current save miscop should be rewritten in
  520. Lisp for portability reasons.
  521.  
  522. The save process under Unix should use the a.out file format and
  523. effectively do purification while creating the file.  The Unix manuals
  524. contain a description of a.out file format.  In the following, I am
  525. assuming that all three stacks have been combined into one and the standard
  526. Unix stack is being used for this combined stack.  To create a Lisp a.out file,
  527. the following steps are necessary:
  528. @begin[Enumerate]
  529. If Lisp is currently allocating space in the dynamic 0 area, a normal GC
  530. should be performed to move all the data into dynamic 1 space.
  531.  
  532. If there is a gap between the text and data segments as on the IBM RT PC,
  533. allocate space to hold the new read-only data area in the text area.  On
  534. machines without this gap, read-only data must be placed in the static
  535. area.  All references to read-only below assume this.
  536.  
  537. Do a purifying GC in which objects are moved into the new read-only area
  538. and to the end of the current static area.  The static area will grow and
  539. either more memory must be allocated to dynamic space or the size of the
  540. dynamic areas must be adjusted appropriately after this purifying GC has
  541. finished.
  542.  
  543. The Lisp is now ready to be saved.  First the header page must be written
  544. out.  This header page includes a magic number that says this is an a.out
  545. file.  It also includes the size of the text segment (read-only data), the
  546. size of the initialized data segment (static data plus amount of stack that
  547. must be saved), the size of the symbol table, and the size of the string
  548. table must be written.  The size of the uninitialized data segment should
  549. be 0.
  550.  
  551. The text (read-only data) segment must be written.  It must be rounded
  552. off to a page boundary.
  553.  
  554. The initialized data (static data) segment must be written.  The part of
  555. the stack that Lisp needs to run must also be written to the file now.
  556. This segment also must be rounded off to a page boundary.
  557.  
  558. The symbol table and string table information from the original Lisp a.out
  559. file or the last intermediate a.out file created by loading C code must be
  560. copied to the file.
  561. @end[Enumerate]
  562. At this point, a new a.out file should have been created.  This file should
  563. be made executable and it should be possible to run and have Lisp restart.
  564.  
  565. One important thing to notice is that when the saved Lisp file starts
  566. executing, it must copy the stack information out of the initialized data
  567. segment into the proper place on the Unix stack.  This should not be
  568. difficult, but may require someone to write some assembly code to do this.
  569. Note that the restarted Lisp should make sure the stack is in the location
  570. it expects -- otherwise the OS has changed out form underneath it and it
  571. will be necessary to recreate the saved file on the new version of the
  572. operating system.
  573.  
  574. @section[Summary]
  575. @label[Summary]
  576.  
  577. I have tried to give a brief summary of how memory should be layed out under
  578. two assumptions: one using Mach virtual memory features and the other using
  579. standard Unix memory allocation.  My belief at this point is that it would
  580. be nice to run in a standard Unix environment, but that it will complicate
  581. everything to such a degree that I don't think it is worth doing.
  582. When the system is running stably on a couple of machines, it might be
  583. worth spending the large amount of time necessary to come up with a good
  584. scheme for dealing with standard Unix (if you wait long enough maybe it
  585. will improve to the point that some of the serious problems are corrected).
  586.  
  587. My recommendation would be to use Mach features and do the following:
  588. @begin[Itemize]
  589. Use the current core file format and the current Lisp start up code and map
  590. the various regions of memory Lisp uses into the process.  Using the a.out
  591. file format would be convenient, but makes it difficult to have stacks out
  592. of the way.
  593.  
  594. Use the Unix stack provided by Mach as the non-lisp or number stack.  This
  595. means the compiler should specify that whatever register is used for this
  596. stack be used as the number stack register.  This stack always grows
  597. downward.
  598.  
  599. Keep the binding and control stacks separate and place them just below the
  600. Unix stack.  On the IBM RT PC the Unix stack is in segment 13, the binding
  601. should be in segment 12, and the control stack in segment 11.  These latter
  602. tow stacks should also grow downward.
  603.  
  604. Vm_allocate the rest of whatever segment the C data is in.  Load C code and
  605. user defined miscops into this area and move Lisp objects here during
  606. purification.  If, as on the IBM RT PC, there are separate text and data
  607. segments, then read-only data could be moved into the text segment.  This
  608. probably isn't worth worrying about.
  609.  
  610. Dynamic space should be allocated using vm_allocate.  When a GC occurs, new
  611. dynamic space should be vm_allocated at that time based on the size of the
  612. current dynamic space and how much space was retained during the previous
  613. GC.  The initial amount of space allocated to dynamic space should be
  614. specified by a command line switch with a reasonable default value (such as
  615. 2 megabytes).  Vm_deallocate the old dynamic space when the GC is finished.
  616. @end[Itemize]
  617.